#include "mainwindow.h"
#include "inputdialog.h"
#include "sortfactory.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QListView>
#include <QMessageBox>
#include <QTextStream>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
      , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    init();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::init()
{
    ui->typeComboBox->setView(new QListView(this));
    ui->typeComboBox->addItems(SortFactory::typeList());

    connect(ui->btnStart, &QPushButton::clicked, this, &MainWindow::startSorting);
    connect(ui->btnStop, &QPushButton::clicked, ui->canvas, &DrawArea::stop);
    connect(ui->btnSkip, &QPushButton::clicked, ui->canvas, &DrawArea::skip);
    connect(ui->btnInput, &QPushButton::clicked, this, &MainWindow::handleInput);

    connect(ui->btnShuffle, &QPushButton::clicked, this, &MainWindow::shuffleData);
    connect(ui->canvas, &DrawArea::runStateChanged, this, &MainWindow::toggleParameter);

    connect(ui->typeComboBox, &QComboBox::currentTextChanged, this, &MainWindow::shuffleData);
    connect(ui->elemSpinBox, &QSpinBox::textChanged, this, &MainWindow::shuffleData);

    connect(ui->actionReadFromFile, &QAction::triggered, this, &MainWindow::readFromFile);
    connect(ui->actionWriteToFile, &QAction::triggered, this, &MainWindow::writeToFile);

    toggleParameter(false);
    shuffleData();
}

void MainWindow::handleInput()
{
    auto *dialog = new InputDialog(this, ui->elemSpinBox->value());
    dialog->show();

    connect(dialog, &InputDialog::deliverArray, this, [this](const std::vector<size_t> &arr) {
        SortBase *method = this->ui->canvas->getSortMethod();
        method->setArray(arr);
        this->update();
    });
}

void MainWindow::shuffleData()
{
    auto const type = ui->typeComboBox->currentIndex();
    SortBase *method = ui->canvas->getSortMethod();

    if (type != ui->canvas->getSortType()) {
        method = SortFactory::generateMethod(type, this);
        ui->canvas->setSortMethod(type, method);
    }

    if ((int) (method->arr.size()) != ui->elemSpinBox->value())
        method->randomArray(ui->elemSpinBox->value());
    else
        method->shuffle();
}

void MainWindow::startSorting()
{
    auto const type = ui->typeComboBox->currentIndex();
    if (type != ui->canvas->getSortType()) {
        SortBase *method = SortFactory::generateMethod(type, this);
        ui->canvas->setSortMethod(type, method);
    }
    ui->canvas->start(ui->elemSpinBox->value(), ui->intervalSpinBox->value());
}

void MainWindow::toggleParameter(bool state)
{
    // enable/disable parameter changes when finished/sorting
    ui->typeComboBox->setEnabled(!state);
    ui->intervalSpinBox->setEnabled(!state);
    ui->elemSpinBox->setEnabled(!state);

    // enable/disable btn state
    ui->btnStart->setEnabled(!state);
    ui->btnShuffle->setEnabled(!state);
    ui->btnSkip->setEnabled(state);
    ui->btnInput->setEnabled(!state);
}

void MainWindow::writeToFile()
{
    QString save_path = QFileDialog::getSaveFileName(this, "选择写入文件", "./");

    // cancel was clicked
    if (save_path.isEmpty())
        return;

    QFile saveFile(save_path);
    if (!saveFile.open(QIODevice::WriteOnly)) {
        // can't open file (e.g. authorization failed)
        QMessageBox::warning(this,
                             tr("打开写入文件"),
                             tr("打开要写入的文件失败，请检查文件名和是否具有写入权限！"));
        return;
    }

    QTextStream out(&saveFile);
    auto &arr = ui->canvas->getSortMethod()->arr;

    std::for_each(arr.begin(), arr.end(), [&out](size_t elem) { out << elem << ' '; });
}

void MainWindow::readFromFile()
{
    QString file_path = QFileDialog::getOpenFileName(this, "选择读取文件", "./");

    // cancel was clicked
    if (file_path.isEmpty())
        return;

    QFile readFile(file_path);
    if (!readFile.open(QIODevice::ReadOnly)) {
        // can't open file (e.g. authorization failed)
        QMessageBox::warning(this,
                             tr("打开读入文件"),
                             tr("打开要读入的文件失败，请检查文件名和是否具有写入权限！"));
        return;
    }

    QTextStream in(&readFile);

    // check validation
    QString raw_data = in.readAll().trimmed();
    if (raw_data.isEmpty()) {
        QMessageBox::warning(this, tr("读取文件"), tr("读取文件内容为空，终止读入"));
        return;
    } else if (raw_data.contains(QRegExp("[^0-9 \\t\\n]"))) {
        QMessageBox::warning(this, tr("读取文件"), tr("读取文件包含非数字字符，终止读入"));
        return;
    }

    // reset to file content, split to array
    in.setString(&raw_data, QIODevice::ReadOnly);
    std::vector<size_t> tmp_arr;
    size_t num;
    while (!in.atEnd()) {
        in >> num;
        tmp_arr.push_back(num);
    }

    // sometime QTextStream will read an extra \0 and translate to 0
    // we need to remove that
    if (tmp_arr.back() == 0)
        tmp_arr.pop_back();

    // setValue will trigger shuffleData
    // so we need to swap the array afterwards
    ui->elemSpinBox->setValue((int) tmp_arr.size());
    ui->canvas->getSortMethod()->arr.swap(tmp_arr);

    this->update();
}
